#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import tkinter as tk
from tkinter import Listbox, Menu, messagebox, scrolledtext
import subprocess
import os
import signal

class TEMUSimulator:
    def __init__(self, root):
        self.root = root
        self.root.title("TEMU Simulator")
        self.root.geometry("1960x1020")
        self.cur_process = None
        self.close_flag = False

        self.create_widgets()
        self.create_menu()

    def create_widgets(self):
        file_btn = tk.Button(self.root, text='File', width=10, command=self.load_file)
        file_btn.pack(side=tk.LEFT)

        compile_btn = tk.Button(self.root, text='Compile', width=10, command=self.compile_code)
        compile_btn.pack(side=tk.LEFT)

        run_btn = tk.Button(self.root, text='Run', width=10, command=self.run_script)
        run_btn.pack(fill=tk.X, pady=10)

        self.txt_out = scrolledtext.ScrolledText(self.root, state='normal')
        self.txt_out.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)

    def create_menu(self):
        menu_bar = Menu(self.root)
        cmd_menu = Menu(menu_bar, tearoff=0)

        cmd_menu_items = {
            'Help': 'help.sh',
            'Register Info': 'infor.sh',
            'Watch Point Info': 'infow.sh',
            'Express Calculator': 'p.sh',
            'Scan Storage': 'x.sh',
            'Delete Watch Point': 'd.sh',
            'Execute In Step': 'si.sh'
        }

        for label, script in cmd_menu_items.items():
            cmd_menu.add_command(label=label, command=lambda s=script: self.run_bash_script(s))

        menu_bar.add_cascade(label="CMD", menu=cmd_menu)
        self.root.config(menu=menu_bar)

    def load_file(self):
        src_dir = os.path.join(os.path.dirname(__file__), 'mips_sc/src')
        asm_files = [f for f in os.listdir(src_dir) if f.endswith('.S')]

        if not asm_files:
            messagebox.showinfo("Info", "No assembly files found in the directory.")
            return

        select_window = tk.Toplevel(self.root)
        select_window.title("Select Assemble File")

        listbox = Listbox(select_window, selectmode=tk.SINGLE, height=10, width=50)
        for file in asm_files:
            listbox.insert(tk.END, file)
        listbox.pack(padx=20, pady=20)

        select_btn = tk.Button(select_window, text='Select', command=lambda: self.select_file(listbox, src_dir, select_window))
        select_btn.pack(pady=10)

    def select_file(self, listbox, src_dir, select_window):
        selection = listbox.curselection()
        if not selection:
            messagebox.showwarning("Warning", "Please select a file.")
            return

        selected_file = listbox.get(selection[0])
        src_file_path = os.path.join(src_dir, selected_file)
        dest_file_path = os.path.join(src_dir, 'test.S')

        try:
            with open(src_file_path, 'rb') as src, open(dest_file_path, 'wb') as dest:
                dest.write(src.read())

            self.update_makefile()
            messagebox.showinfo("Success", f"File '{selected_file}' loaded as 'test.S'.")
            select_window.destroy()
        except Exception as e:
            messagebox.showerror("Error", f"Failed to load file: {e}")

    def update_makefile(self):
        makefile_path = os.path.join(os.path.dirname(__file__), 'mips_sc/src/Makefile.testcase')
        with open(makefile_path, 'w') as f:
            f.write('USER_PROGRAM := test')

    def compile_code(self):
        self.execute_command("make clean && cd mips_sc/ && make", "Compile succeed!\n")

    def run_script(self):
        script_path = os.path.join(os.path.dirname(__file__), 'temu/test/gui.sh')
        self.run_bash_script(script_path)

    def run_bash_script(self, script_name):
        script_path = os.path.join(os.path.dirname(__file__), 'temu/test', script_name)
        self.execute_command(f"bash {script_path}", f"{script_name} executed successfully!")

    def execute_command(self, command, success_msg):
        # 删除现有文本框内容
        self.txt_out.delete(1.0, tk.END)

        # 创建子进程以执行命令
        process = subprocess.Popen(command, shell=True, preexec_fn=os.setsid, stderr=subprocess.PIPE, stdout=subprocess.PIPE)

        # 持续读取输出和错误流
        while True:
            # 尝试从标准输出读取一行
            output = process.stdout.readline()
            if output:
                self.txt_out.insert(tk.END, output.decode())
                self.txt_out.see(tk.END)  # 自动滚动到最新输出

            # 尝试从标准错误读取一行
            errput = process.stderr.readline()
            if errput:
                self.txt_out.insert(tk.END, errput.decode(), 'error')
                self.txt_out.see(tk.END)

            # 更新 GUI 界面
            self.root.update_idletasks()

            # 判断子进程是否完成
            if process.poll() is not None and not output and not errput:
                break

        # 判断子进程返回码
        if process.returncode == 0:
            self.txt_out.insert(tk.END, success_msg)
        else:
            self.txt_out.insert(tk.END, "Command execution failed.\n")

    def on_closing(self):
        if self.cur_process:
            if messagebox.askokcancel("Quit", "There is a task running, do you want to quit?"):
                os.killpg(os.getpgid(self.cur_process.pid), signal.SIGTERM)
                self.cur_process = None
            else:
                return
        self.close_flag = True
        self.root.destroy()

def main():
    root = tk.Tk()
    app = TEMUSimulator(root)
    root.protocol("WM_DELETE_WINDOW", app.on_closing)
    root.mainloop()

if __name__ == "__main__":
    main()